<?php

/**
 * @Author: Wang chunsheng  email:2192138785@qq.com
 * @Date:   2023-04-24 14:58:10
 * @Last Modified by:   Wang chunsheng  email:2192138785@qq.com
 * @Last Modified time: 2023-07-28 14:25:32
 */

namespace Common\Services;

use Common\Helpers\StringHelper;
use Common\Libs\Jwt\Exception;
use Common\Libs\Jwt\Jwt;
use Common\Models\ApiAccessToken;
use Common\Models\Member;
use Common\Services\Sys\ProjectService;
use Hyperf\Context\ApplicationContext;
use Hyperf\Contract\ConfigInterface;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;

// https: //cloud.tencent.com/developer/article/2000236
class JwtService
{
    /**
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     */
    public static function getConfig()
    {
        /**
         * @var ConfigInterface $config
         */
        $config = ApplicationContext::getContainer()->get(ConfigInterface::class);

        return $config->get('jwt');
    }

    /**
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     * @throws \Exception
     */
    public static function createToken($username, $password, $project_id): array
    {
        $member = Member::query()
            ->with('getAccessToken')
            ->where('username', $username)
            ->select('member_id', 'username', 'mobile', 'password_hash', 'status', 'address', 'nickName', 'avatarUrl', 'gender', 'country', 'province', 'realname')
            ->first();

        if (!$member) {
            return [
                'status' => 400,
                'message' => '用户名不存在',
                'data' => null,
            ];
        }

        $config = self::getConfig();
        $SecretKey = $config['SecretKey'];
        $jwtObject = Jwt::getInstance()
            ->setSecretKey($SecretKey) // 秘钥
            ->publish();

        $Iss = $config['Iss'];
        $Sub = $config['Sub'];
        $jwtObject->setAlg('HMACSHA256'); // 加密方式
        $jwtObject->setAud($username); // 用户
        $jwtObject->setExp(time() + 3600); // 过期时间
        $jwtObject->setIat(time()); // 发布时间
        $jwtObject->setIss($Iss); // 发行人
        $jwtObject->setJti(md5(time())); // jwt id 用于标识该jwt
        $jwtObject->setNbf(time() + 60 * 5); // 在此之前不可用
        $jwtObject->setSub($Sub); // 主题

        $checkPass = self::checkPassword($member, $password);
        if (!$checkPass) {
            return [
                'status' => 400,
                'message' => '密码错误',
                'data' => null,
            ];
        }

        $tokens = $member->getAccessToken;
        $access_token = '';
        $refresh_token = '';
        $refresh_time = time();
        if($tokens){
            $access_token = $tokens['access_token'];
            $refresh_token = $tokens['refresh_token'];
            $refresh_time = $tokens['refresh_time'];
        }

        // 校验有效期
        if ($refresh_time < time()) {
            $refresh_token = StringHelper::random(30);
            MemberService::editRefToken($member['member_id'], $refresh_token);
        }

        unset($member['getAccessToken'], $member['password_hash']);
        // 自定义数据
        $jwtObject->setData([
            'member' => [
                'member_id' => $member['member_id'],
                'username' => $member['username'],
                'mobile' => $member['mobile'],
                'address' => $member['address'],
                'nickName' => $member['nickName'],
                'avatarUrl' => $member['avatarUrl'],
                'gender' => $member['gender'],
                'country' => $member['country'],
                'province' => $member['province'],
                'realname' => $member['realname'],
            ]
        ]);

        // 最终生成的token
        $token = $jwtObject->__toString();
        $access_token = self::encrypt_ecb($token);
        MemberService::editToken($member['member_id'], $access_token);
        return [
            'status' => 200,
            'type' => 'login_res',
            'message' => '登录成功',
            'data' => [
                'member' => [
                    'member_id' => $member['member_id'],
                    'username' => $member['username'],
                    'mobile' => $member['mobile'],
                    'address' => $member['address'],
                    'nickName' => $member['nickName'],
                    'avatarUrl' => $member['avatarUrl'],
                    'gender' => $member['gender'],
                    'country' => $member['country'],
                    'province' => $member['province'],
                    'realname' => $member['realname'],
                ],
                'project_id' => $project_id,
                'access_token' => $access_token,
                'refresh_token' => $refresh_token,
            ],
        ];
    }

    /**
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     */
    public static function flushToken($refresh_token, $project_id): array
    {
        $member_id = ApiAccessToken::query()->where(['refresh_token' => $refresh_token])->value('member_id');

        if (!$member_id) {
            return [
                'status' => 400,
                'message' => 'refresh_token不正确',
                'data' => null,
            ];
        }
        $member = Member::query()
            ->select('member_id', 'username', 'mobile', 'password_hash', 'status', 'address', 'nickName', 'avatarUrl', 'gender', 'country', 'province', 'realname')
            ->where(['member_id' => $member_id])
            ->first();

        if (!$member) {
            return [
                'status' => 400,
                'message' => '用户不存在',
                'data' => null,
            ];
        }

        $username = $member['username'];

        $config = self::getConfig();
        $SecretKey = $config['SecretKey'];
        $jwtObject = Jwt::getInstance()
            ->setSecretKey($SecretKey) // 秘钥
            ->publish();

        $Iss = $config['Iss'];
        $Sub = $config['Sub'];
        $jwtObject->setAlg('HMACSHA256'); // 加密方式
        $jwtObject->setAud($username); // 用户
        $jwtObject->setExp(time() + 3600); // 过期时间
        $jwtObject->setIat(time()); // 发布时间
        $jwtObject->setIss($Iss); // 发行人
        $jwtObject->setJti(md5(time())); // jwt id 用于标识该jwt
        $jwtObject->setNbf(time() + 60 * 5); // 在此之前不可用
        $jwtObject->setSub($Sub); // 主题


        $tokens = $member->getAccessToken;
        $refresh_token = $tokens['refresh_token'];
        unset($member['getAccessToken'], $member['password_hash']);
        // 自定义数据
        $jwtObject->setData([
            'member' => [
                'member_id' => $member['member_id'],
                'username' => $member['username'],
                'mobile' => $member['mobile'],
                'address' => $member['address'],
                'nickName' => $member['nickName'],
                'avatarUrl' => $member['avatarUrl'],
                'gender' => $member['gender'],
                'country' => $member['country'],
                'province' => $member['province'],
                'realname' => $member['realname'],
            ]
        ]);

        // 最终生成的token
        $token = $jwtObject->__toString();

        $access_token = self::encrypt_ecb($token);
        MemberService::editToken($member['member_id'], $access_token);

        return [
            'status' => 200,
            'type' => 'login_res',
            'message' => '刷新token成功',
            'data' => [
                'member' => [
                    'member_id' => $member['member_id'],
                    'username' => $member['username'],
                    'mobile' => $member['mobile'],
                    'address' => $member['address'],
                    'nickName' => $member['nickName'],
                    'avatarUrl' => $member['avatarUrl'],
                    'gender' => $member['gender'],
                    'country' => $member['country'],
                    'province' => $member['province'],
                    'realname' => $member['realname'],
                ],
                'project_id' => $project_id,
                'access_token' => $access_token,
                'refresh_token' => $refresh_token,
            ],
        ];
    }

    /**
     * @param $token
     * @return array
     * @throws ContainerExceptionInterface
     * @throws Exception
     * @throws NotFoundExceptionInterface
     */
    public static function getUser($token): array
    {
        $token = self::decrypt_ecb($token);
        $jwtObject = Jwt::getInstance()->decode($token);
        return $jwtObject->getData();
    }

    /**
     * @throws \Exception
     */
    public static function checkPassword($member, $password): bool
    {
        $hash = $member['password_hash'];
        $PasswordService = new PasswordService();
        return $PasswordService->validatePassword($password, $hash);
    }

    /**
     * AES-256-ECB 加密.
     *
     * @param $data
     *
     * @return string
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     */
    public static function encrypt_ecb($data): string
    {
        $config = self::getConfig();
        $SecretKey = $config['SecretKey'];
        $text = openssl_encrypt($data, 'AES-256-ECB', $SecretKey, 1);

        return base64_encode($text);
    }

    /**
     * AES-256-ECB 解密.
     *
     * @param $text
     *
     * @return string
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     */
    public static function decrypt_ecb($text): string
    {
        $config = self::getConfig();
        $SecretKey = $config['SecretKey'];
        $decodeText = base64_decode($text);
        return openssl_decrypt($decodeText, 'AES-256-ECB', $SecretKey, 1);
    }
}
